<?php

namespace addons\yunfood\controller;

use addons\yunfood\library\Logic;
use addons\yunfood\library\PayService;
use addons\yunfood\model\Config;
use addons\yunfood\model\FundOrder;
use addons\yunfood\model\Order;
use addons\yunfood\model\OrderRefund;
use addons\yunfood\model\Payment;
use addons\yunfood\model\Refundment;
use addons\yunfood\model\UserAuth;
use think\Db;
use think\Exception;
use think\exception\PDOException;
use think\Log;
use think\Session;

/**
 * 通知
 */
class Web extends \think\addons\Controller
{
    protected $noNeedLogin = ['*'];
    protected $layout = '';

    // 支付回调
    public function payCallback()
    {
        $type = $this->request->param('type');

        return PayService::notifyPayment($type, function ($data, $pay) use ($type) {
            Log::write('获得支付结果=' . json_encode($data));
            try {
                // 支付成功才标记
                if ($data['paymentStatus']) {
                    $this->payFinish($data['paymentTradeNo'], $data['paymentAmount']);
                }
            } catch (Exception $e) {
                if ($e->getMessage() !== '已支付成功') {
                    return $e->getMessage();
                }
            }
            return $pay->success()->send();
        });
    }

    // 支付成功
    private function payFinish($tradeNo, $payAmount)
    {
        // 开启事务
        Db::startTrans();
        try {
            if (! $payment = Payment::where('trade_no', $tradeNo)->lock(true)->find()) {
                throw new Exception('支付信息不存在');
            }
            if ($payment->status == Payment::STATUS_DONE) {
                throw new Exception('已支付成功');
            }
            $payment->finish_time = time();
            $payment->status = Payment::STATUS_DONE;
            $payment->save();

            if ($payment->order_type === Payment::ORDER_TYPE_GOODS) {
                Order::finishOrder($payment->order_no, $payment->goods_amount, $payment->channelText);
            } elseif ($payment->order_type === Payment::ORDER_TYPE_FUND) {
                FundOrder::finishOrder($payment->order_no, $payment->goods_amount, $payment->channelText);
            }
            Db::commit();
        } catch (PDOException | Exception $e) {
            Db::rollback();
            throw $e;
        }
    }

    // 退款回调
    public function refundCallback()
    {
        $type = $this->request->param('type');

        return PayService::notifyRefundment($type, function ($data, $pay) use ($type) {
            Log::write('获得退款结果=' . json_encode($data));
            try {
                $this->refundComplete($data['refundmentTradeNo'], $data['refundmentAmount'], $data['refundmentStatus']);
            } catch (Exception $e) {
                if ($e->getMessage() !== '已退款完成') {
                    return $e->getMessage();
                }
            }
            return $pay->success()->send();
        });
    }

    // 退款完成
    private function refundComplete($tradeNo, $refundAmount, $refundStatus)
    {
        // 开启事务
        Db::startTrans();
        try {
            if (! $refundment = Refundment::where('trade_no', $tradeNo)->lock(true)->find()) {
                throw new Exception('退款信息不存在');
            }
            if (in_array($refundment->status, [Refundment::STATUS_DONE, Refundment::STATUS_FAIL])) {
                throw new Exception('已退款完成');
            }
            $refundment->finish_time = time();
            $refundment->status = $refundStatus ? Refundment::STATUS_DONE : Refundment::STATUS_FAIL;
            $refundment->save();

            if ($refundment->from_type === Refundment::FROM_TYPE_ORDER) {
                $refundmentStatus = $refundStatus ? OrderRefund::REFUNDMENT_STATUS_DONE : OrderRefund::REFUNDMENT_STATUS_FAIL;
                OrderRefund::finishRefund($refundment->from_no, $refundmentStatus);
            }
            Db::commit();
        } catch (PDOException | Exception $e) {
            Db::rollback();
            Log::write('失败原因', $e->getMessage());
            throw $e;
        }
    }

    // 网页登录
    public function connect()
    {
        $url = $this->request->request('url', $this->request->server('HTTP_REFERER', '/', 'trim'), 'trim');
        if (! $url) {
            $this->error('参数错误');
        }
        Session::set('redirectUrl', $url);

        // 跳转到登录授权页面
        $state = md5(uniqid(rand(), true));
        Session::set('state', $state);
        $params = [
            'appid'         => Config::getGroupAttribute(Config::GROUP_MP, 'app_id'),
            'redirect_uri'  => addon_url('yunfood/web/callback', [], false, true),
            'response_type' => 'code',
            'scope'         => 'snsapi_base',
            'state'         => $state,
        ];
        $authUrl = 'https://open.weixin.qq.com/connect/oauth2/authorize';
        $authUrl .= '?' . http_build_query($params) . '#wechat_redirect';
        $this->redirect($authUrl);
    }

    // 网页登录回调
    public function callback()
    {
        $code = $this->request->get('code');
        if (! $code) {
            $this->error('code不能为空');
        }
        if (isset($params['state']) && $params['state'] != Session::get('state')) {
            $this->error('state不正确');
        }
        $userInfo = Logic::getMpCodeData($code);

        // 成功后返回之前页面
        $url = Session::has('redirectUrl') ? Session::pull('redirectUrl') : '';
        if (! $url) {
            $this->error('没有跳转地址');
        }
        $authKey = Logic::getUserAuthKey($userInfo['openid'], UserAuth::SOURCE_MP);
        $url .= (strpos($url, '?') !== false ? '&' : '?') . 'auth_key=' . $authKey;
        $this->redirect($url);
    }
}
